package com.smile.frame.config.oss;


import com.aliyun.oss.OSSClient;
import com.aliyun.oss.model.OSSObject;
import com.aliyun.oss.model.ObjectMetadata;
import com.smile.frame.config.oss.config.AliyunOSSConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.net.URL;
import java.util.Date;
import java.util.Iterator;
import java.util.Objects;
import java.util.UUID;

@Slf4j
@Component
public class AliyunOSSUtils {

    @Autowired
    private AliyunOSSConfig aliyunOSSConfig;

    /**
     * 默认参数文件上传
     *
     * @param file File
     * @return
     */
    public String uploadFile(File file) {
        if (Objects.isNull(file)) {
            log.info("文件为空");
            return null;
        }
        try {
            return uploadFileInputStream(new FileInputStream(file), file.getName(), null, null);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 默认参数文件上传 从request获取富文本中文件流
     *
     * @param request HttpServletRequest
     * @return
     */
    public String uploadHttpServletRequest(HttpServletRequest request) {
        //富文本图片
        MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
        Iterator item = multipartRequest.getFileNames();
        String fileName = (String) item.next();
        MultipartFile file = multipartRequest.getFile(fileName);
        if (Objects.isNull(file)) {
            log.info("文件为空");
            return null;
        }
        return uploadMultipartFile(file);
    }

    /**
     * 默认参数文件上传
     *
     * @param file MultipartFile
     * @return
     */
    public String uploadMultipartFile(MultipartFile file) {
        if (Objects.isNull(file)) {
            log.info("文件为空");
            return null;
        }
        try {
            // 文件流
            InputStream is = file.getInputStream();
            // 文件名
            String fileName = file.getOriginalFilename();
            // 文件大小
            Long fileSize = file.getSize();
            // 分装 ObjectMetadata 对象
            ObjectMetadata metadata = createObjectMetadata(is, fileName, fileSize);

            return uploadFileInputStream(is, fileName, metadata, null);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 默认参数文件上传
     *
     * @param is InputStream
     * @return
     */
    public String uploadFileInputStream(InputStream is, String fileName) {
        if (Objects.isNull(is)) {
            log.info("文件为空");
            return null;
        }
        return uploadFileInputStream(is, fileName, null, null);
    }

    /**
     * 默认文件流上传
     *
     * @param is         文件流
     * @param fileName   文件名称
     * @param metadata   ObjectMetadata 参数对象
     * @param expiration expiration url有效时间 不传默认为10年
     * @return
     */
    private String uploadFileInputStream(InputStream is, String fileName, ObjectMetadata metadata, Date expiration) {
        if (Objects.isNull(expiration)) {
            // 默认URL访问有效时间为 10 年
            expiration = new Date(System.currentTimeMillis() + 3600L * 1000 * 24 * 365 * 10);
        }
        OSSClient ossClient = aliyunOSSConfig.createOSSClient();
        try {
            return upload(ossClient, is, aliyunOSSConfig.getBucket_name(), aliyunOSSConfig.getFolder(), fileName, expiration, metadata);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 上传图片至OSS
     *
     * @param ossClient  oss连接
     * @param is         上传文件流
     * @param bucketName 存储空间名
     * @param folder     文件夹名
     * @param fileName   文件名
     * @param expiration url有效时间
     * @return
     */
    private String upload(OSSClient ossClient, InputStream is, String bucketName, String folder, String fileName, Date expiration,
                          ObjectMetadata metadata) {
        String url = null;
        try {
            String fileExtension = fileName.substring(fileName.lastIndexOf("."));
            fileName = UUID.randomUUID().toString().replaceAll("-", "");
            String key = "";
            if (folder.lastIndexOf("/") > 0) {
                key = folder + fileName + fileExtension;
            } else {
                key = folder + "/" + fileName + fileExtension;
            }
            if (Objects.isNull(metadata)) {
                ossClient.putObject(bucketName, key, is);
            } else {
                ossClient.putObject(bucketName, key, is, metadata);
            }

            URL tempUrl = ossClient.generatePresignedUrl(bucketName, key, expiration);
            url = tempUrl.toString().split("\\?")[0];
        } catch (Exception e) {
            e.printStackTrace();
            log.info("上传存储空间{}的文件失败,OSS服务器异常", bucketName);
        } finally {
            // 释放资源
            ossClient.shutdown();
            try {
                if (is != null) {
                    is.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return url;
    }

    /**
     * 根据key删除OSS服务器上的文件
     *
     * @param filePath 文件相对路径
     */
    public void deleteFile(String filePath) {
        OSSClient ossClient = aliyunOSSConfig.createOSSClient();
        ossClient.deleteObject(aliyunOSSConfig.getBucket_name(), filePath);
        log.info("删除存储空间{}下的文件{}成功", aliyunOSSConfig.getBucket_name(), filePath);
    }

    /**
     * 根据key删除OSS服务器上的文件
     *
     * @param bucketName 存储空间
     * @param folder     模拟文件夹名
     * @param fileName   cake.jpg
     */
    public void deleteFile(String bucketName, String folder, String fileName) {
        String key = "";
        if (folder.lastIndexOf("/") > 0) {
            key = folder + fileName;
        } else {
            key = folder + "/" + fileName;
        }
        deleteFile(key);
    }

    /**
     * 创建模拟文件夹
     *
     * @param ossClient  oss连接
     * @param bucketName 存储空间
     * @param folder     模拟文件夹名如
     * @return 文件夹名
     */
    private String createFolder(OSSClient ossClient, String bucketName, String folder) {
        // 文件夹名
        final String keySuffixWithSlash = folder;
        // 判断文件夹是否存在，不存在则创建
        if (!ossClient.doesObjectExist(bucketName, keySuffixWithSlash)) {
            // 创建文件夹
            ossClient.putObject(bucketName, keySuffixWithSlash, new ByteArrayInputStream(new byte[0]));
            log.info("创建存储空间{}下的文件夹{}成功", bucketName, folder);
            // 得到文件夹名
            OSSObject object = ossClient.getObject(bucketName, keySuffixWithSlash);
            return object.getKey();
        }
        return keySuffixWithSlash;
    }

    /**
     * 通过文件名判断并获取OSS服务文件上传时文件的contentType
     *
     * @param fileName 文件名
     * @return 文件的contentType
     */
    public static String getContentType(String fileName) {
        // 文件的后缀名
        String fileExtension = fileName.substring(fileName.lastIndexOf("."));
        if (".bmp".equalsIgnoreCase(fileExtension)) {
            return "image/bmp";
        }
        if (".gif".equalsIgnoreCase(fileExtension)) {
            return "image/gif";
        }
        if (".jpeg".equalsIgnoreCase(fileExtension) || ".jpg".equalsIgnoreCase(fileExtension)) {
            return "image/jpeg";
        }
        if (".png".equalsIgnoreCase(fileExtension)) {
            return "image/png";
        }
        if (".html".equalsIgnoreCase(fileExtension)) {
            return "text/html";
        }
        if (".txt".equalsIgnoreCase(fileExtension)) {
            return "text/plain";
        }
        if (".vsd".equalsIgnoreCase(fileExtension)) {
            return "application/vnd.visio";
        }
        if (".ppt".equalsIgnoreCase(fileExtension) || "pptx".equalsIgnoreCase(fileExtension)) {
            return "application/vnd.ms-powerpoint";
        }
        if (".doc".equalsIgnoreCase(fileExtension) || "docx".equalsIgnoreCase(fileExtension)) {
            return "application/msword";
        }
        if (".xml".equalsIgnoreCase(fileExtension)) {
            return "text/xml";
        }
        // 默认返回类型
        return "";
    }

    /**
     * 封装 ObjectMetadata 对象
     *
     * @param is
     * @param fileName
     * @param fileSize
     * @return
     */
    public ObjectMetadata createObjectMetadata(InputStream is, String fileName, Long fileSize) throws IOException {
        // 创建上传Object的Metadata
        ObjectMetadata metadata = new ObjectMetadata();
        // 上传的文件的长度
        metadata.setContentLength(is.available());
        // 指定该Object被下载时的网页的缓存行为
        metadata.setCacheControl("no-cache");
        // 指定该Object下设置Header
        metadata.setHeader("Pragma", "no-cache");
        // 指定该Object被下载时的内容编码格式
        metadata.setContentEncoding("utf-8");
        // 文件的MIME，定义文件的类型及网页编码，决定浏览器将以什么形式、什么编码读取文件。如果用户没有指定则根据Key或文件名的扩展名生成，默认值application/octet-stream
        metadata.setContentType(getContentType(fileName));
        // 指定该Object被下载时的名称（指示MINME用户代理如何显示附加的文件，打开或下载，及文件名称）
        metadata.setContentDisposition("filename/filesize=" + fileName + "/" + fileSize + "Byte.");
        return metadata;
    }

}